#include "client.h"
#include <QFile>
#include <QFileInfo>
#include <QCoreApplication>
#include <QThread>
#include <QUuid>
#include <QCryptographicHash>
#include <QEventLoop>
#include <QTimer>
#include <QBuffer>
#include <zlib.h>

// 添加static关键字避免链接时的多重定义错误
// 数据压缩函数
static QByteArray compressData(const QByteArray &data, int level = Z_BEST_COMPRESSION) {
    if (data.isEmpty())
        return QByteArray();

    // 计算压缩后最大可能的大小
    uLongf compressedSize = compressBound(data.size());
    QByteArray compressed;
    compressed.resize(compressedSize);

    // 压缩数据
    int result = compress2((Bytef*)compressed.data(), &compressedSize, 
                           (const Bytef*)data.data(), data.size(), level);
    
    if (result != Z_OK) {
        // 压缩失败，返回原始数据
        return data;
    }

    // 调整压缩后数据的大小
    compressed.resize(compressedSize);
    return compressed;
}

// 添加static关键字避免链接时的多重定义错误
// 数据解压缩函数
static QByteArray decompressData(const QByteArray &compressedData, int originalSize) {
    if (compressedData.isEmpty())
        return QByteArray();

    QByteArray decompressed;
    decompressed.resize(originalSize);
    
    uLongf decompressedSize = originalSize;
    
    // 解压缩数据
    int result = uncompress((Bytef*)decompressed.data(), &decompressedSize,
                           (const Bytef*)compressedData.data(), compressedData.size());
    
    if (result != Z_OK) {
        // 解压缩失败
        return QByteArray();
    }
    
    // 调整解压缩后数据的大小
    decompressed.resize(decompressedSize);
    return decompressed;
}

Client::Client(QObject *parent) : QObject(parent), authenticated(false), serverPort(0), receivingScreenUpdates(false)
{
    networkManager = new NetworkManager(this);
    
    // 连接网络管理器信号
    connect(networkManager, &NetworkManager::connectionStatusChanged, 
            this, &Client::connectionStatusChanged);
    
    connect(networkManager, &NetworkManager::dataReceived, 
            this, &Client::onDataReceived);
    
    connect(networkManager, &NetworkManager::errorOccurred, 
            this, &Client::onNetworkError);
    
    LOG_INFO("客户端初始化完成");
}

Client::~Client()
{
    disconnectFromServer();
}

bool Client::connectToServer(const QString &host, quint16 port)
{
    serverHost = host;
    serverPort = port;
    
    LOG_INFO(QString("尝试连接到服务器: %1:%2").arg(host).arg(port));
    
    return networkManager->connectToHost(host, port);
}

void Client::disconnectFromServer()
{
    if (networkManager->isConnected()) {
        LOG_INFO("断开与服务器的连接");
        
        if (authenticated) {
            // 发送断开连接消息
            QJsonObject data;
            data["reason"] = "用户主动断开";
            networkManager->sendData(MessageType::Disconnect, data);
        }
        
        // 重置屏幕更新状态
        receivingScreenUpdates = false;
        
        networkManager->disconnectFromHost();
        authenticated = false;
    }
}

bool Client::sendMouseEvent(int x, int y, int button, bool pressed)
{
    if (!authenticated) {
        LOG_WARNING("发送鼠标事件失败: 未认证");
        return false;
    }
    
    QJsonObject data;
    data["x"] = x;
    data["y"] = y;
    data["button"] = button;
    data["pressed"] = pressed;
    
    return networkManager->sendData(MessageType::MouseEvent, data);
}

bool Client::sendKeyboardEvent(int key, bool pressed)
{
    if (!authenticated) {
        LOG_WARNING("发送键盘事件失败: 未认证");
        return false;
    }
    
    // 过滤无效的键值
    if (key <= 0) {
        LOG_WARNING(QString("无效的键值: %1").arg(key));
        return false;
    }
    
    QJsonObject data;
    data["key"] = key;
    data["pressed"] = pressed;
    
    LOG_INFO(QString("发送键盘事件: 键值=%1, %2")
            .arg(key)
            .arg(pressed ? "按下" : "释放"));
    
    // 尝试发送事件，最多重试2次
    for (int attempt = 0; attempt < 3; attempt++) {
        if (networkManager->sendData(MessageType::KeyboardEvent, data)) {
            if (attempt > 0) {
                LOG_INFO(QString("键盘事件发送成功 (尝试 %1/3)").arg(attempt + 1));
            }
            return true;
        }
        
        LOG_WARNING(QString("键盘事件发送失败，尝试 %1/3").arg(attempt + 1));
        
        // 如果是最后一次尝试，不再等待
        if (attempt < 2) {
            QThread::msleep(50); // 短暂等待后重试
        }
    }
    
    LOG_ERROR(QString("多次尝试发送键盘事件均失败: 键值=%1, %2")
            .arg(key)
            .arg(pressed ? "按下" : "释放"));
    
    return false;
}

bool Client::requestScreenData()
{
    if (!authenticated) {
        LOG_WARNING("请求屏幕数据失败: 未认证");
        return false;
    }
    
    QJsonObject data;
    data["fullscreen"] = true;  // 请求完整屏幕
    
    return networkManager->sendData(MessageType::ScreenData, data);
}

bool Client::authenticate(const QString &username, const QString &password)
{
    if (!networkManager->isConnected()) {
        LOG_WARNING("认证失败: 未连接到服务器");
        return false;
    }
    
    QJsonObject data;
    data["username"] = username;
    data["password"] = password;
    
    LOG_INFO(QString("发送身份验证请求: 用户名=%1").arg(username));
    
    return networkManager->sendData(MessageType::Authenticate, data);
}

bool Client::isConnected() const
{
    return networkManager->isConnected();
}

bool Client::startScreenUpdates(int fps)
{
    if (!authenticated) {
        LOG_WARNING("启动屏幕更新失败: 未认证");
        return false;
    }
    
    if (receivingScreenUpdates) {
        LOG_INFO("已经在接收屏幕更新");
        return true;
    }
    
    LOG_INFO(QString("请求开始连续接收屏幕更新, FPS: %1").arg(fps));
    
    QJsonObject data;
    data["fullscreen"] = true;
    data["continuous"] = true;
    data["fps"] = fps;
    
    bool result = networkManager->sendData(MessageType::ScreenData, data);
    if (result) {
        receivingScreenUpdates = true;
    }
    
    return result;
}

void Client::stopScreenUpdates()
{
    if (!authenticated || !receivingScreenUpdates) {
        return;
    }
    
    LOG_INFO("请求停止屏幕更新");
    
    QJsonObject data;
    data["continuous"] = false;
    
    networkManager->sendData(MessageType::ScreenData, data);
    receivingScreenUpdates = false;
}

bool Client::isReceivingScreenUpdates() const
{
    return receivingScreenUpdates;
}

void Client::onDataReceived(MessageType type, const QJsonObject &data)
{
    switch (type) {
    case MessageType::Connect: {
        LOG_INFO("收到连接响应: " + data["message"].toString());
        break;
    }
    case MessageType::Authenticate: {
        bool success = data["success"].toBool();
        QString message = data["message"].toString();
        
        if (success) {
            authenticated = true;
        } else {
            authenticated = false;
        }
        
        LOG_INFO(QString("认证结果: %1 - %2").arg(success ? "成功" : "失败").arg(message));
        emit authenticationResult(success, message);
        break;
    }
    case MessageType::ScreenData: {
        if (!authenticated) {
            LOG_WARNING("收到屏幕数据，但未认证");
            return;
        }
        
        QString base64Data = data["imageData"].toString();
        QByteArray imageData = QByteArray::fromBase64(base64Data.toLatin1());
        
        // 检查数据是否压缩
        bool isCompressed = data.contains("compressed") ? data["compressed"].toBool() : false;
        int originalSize = data.contains("originalSize") ? data["originalSize"].toInt() : imageData.size();
        
        // 如果数据已压缩，则解压缩
        if (isCompressed && originalSize > imageData.size()) {
            QByteArray decompressed = decompressData(imageData, originalSize);
            if (!decompressed.isEmpty()) {
                LOG_INFO(QString("屏幕数据解压缩成功: %1KB -> %2KB (压缩率: %3%)")
                        .arg(imageData.size() / 1024.0, 0, 'f', 1)
                        .arg(decompressed.size() / 1024.0, 0, 'f', 1)
                        .arg(100.0 - (imageData.size() * 100.0 / decompressed.size()), 0, 'f', 1));
                imageData = decompressed;
            } else {
                LOG_ERROR("屏幕数据解压缩失败，使用原始数据");
            }
        }
        
        int width = data["width"].toInt();
        int height = data["height"].toInt();
        
        emit screenDataUpdated(imageData, width, height);
        break;
    }
    case MessageType::Disconnect: {
        QString reason = data["reason"].toString();
        LOG_INFO(QString("服务器断开连接: %1").arg(reason));
        authenticated = false;
        networkManager->disconnectFromHost();
        emit connectionStatusChanged(false);
        break;
    }
    case MessageType::Error: {
        QString message = data["message"].toString();
        LOG_ERROR(QString("服务器错误: %1").arg(message));
        emit errorOccurred(message);
        break;
    }
    case MessageType::FileSendRequest: {
        LOG_INFO("收到文件发送请求响应: " + data["message"].toString());
        if (data.contains("path")) {
            LOG_INFO("服务器将保存文件到: " + data["path"].toString());
        }
        break;
    }
    case MessageType::FileSendData: {
        LOG_INFO("收到文件数据响应");
        break;
    }
    case MessageType::FileSendFinish: {
        bool success = data["success"].toBool();
        QString message = data["message"].toString();
        LOG_INFO(QString("文件发送结果: %1 - %2").arg(success ? "成功" : "失败").arg(message));
        
        if (data.contains("path")) {
            LOG_INFO("文件最终保存路径: " + data["path"].toString());
        }
        break;
    }
    default:
        LOG_WARNING(QString("未处理的消息类型: %1").arg(static_cast<int>(type)));
        break;
    }
}

void Client::onNetworkError(const QString &errorMsg)
{
    LOG_ERROR(QString("网络错误: %1").arg(errorMsg));
    
    if (authenticated) {
        authenticated = false;
        emit connectionStatusChanged(false);
    }
    
    emit errorOccurred(errorMsg);
}

// 在循环外部定义一个函数，用于发送文件传输完成消息并等待确认
bool Client::sendFileFinishMessage(const QString &transferId, const QString &fileName, qint64 fileSize, int totalBlocks, const QByteArray &fileChecksum)
{
    LOG_INFO("准备发送文件传输完成消息...");
    
    // 最多尝试3次发送完成消息
    for (int attempt = 1; attempt <= 3; attempt++) {
        LOG_INFO(QString("发送文件传输完成消息 (尝试 %1/3)").arg(attempt));
        
        // 构建完成消息
        QJsonObject finishObj;
        finishObj["transferId"] = transferId;
        finishObj["clientId"] = transferId;
        finishObj["fileName"] = fileName;
        finishObj["fileSize"] = QString::number(fileSize);
        finishObj["totalBlocks"] = totalBlocks;
        finishObj["checksum"] = QString(fileChecksum.toHex());
        
        if (!networkManager->sendData(MessageType::FileSendFinish, finishObj)) {
            LOG_ERROR("发送完成消息失败");
            // 等待一会儿再尝试
            QThread::msleep(1000);
            continue;
        }
        
        // 等待服务器的传输完成确认
        LOG_INFO("等待服务器的传输完成确认...");
        QEventLoop finishLoop;
        QTimer finishTimer;
        finishTimer.setSingleShot(true);
        bool finishSuccess = false;
        QString resultMessage;
        
        // 连接超时定时器
        connect(&finishTimer, &QTimer::timeout, &finishLoop, &QEventLoop::quit);
        
        // 设置接收服务器确认的处理函数
        auto finishHandler = [this, &finishLoop, &finishSuccess, &resultMessage, transferId](MessageType type, const QJsonObject &data) {
            if (type == MessageType::FileSendFinish) {
                QString recvTransferId = data["transferId"].toString();
                if (recvTransferId == transferId) {
                    finishSuccess = data["success"].toBool();
                    resultMessage = data["message"].toString();
                    LOG_INFO(QString("收到服务器传输完成确认: %1").arg(resultMessage));
                    finishLoop.quit();
                    return true;
                }
            }
            return false;
        };
        
        // 临时注册消息处理函数
        networkManager->registerTemporaryHandler(finishHandler);
        
        // 启动超时定时器并等待，每次尝试减少超时时间
        finishTimer.start(3000 + attempt * 1000); // 3秒 + 尝试次数 * 1秒
        finishLoop.exec();
        
        // 检查是否超时
        if (finishTimer.isActive()) {
            finishTimer.stop();
            // 如果收到了成功的确认，返回成功
            if (finishSuccess) {
                LOG_INFO(QString("文件发送完成确认: %1").arg(resultMessage));
                emit fileSendFinished(true, resultMessage.isEmpty() ? "文件发送完成" : resultMessage);
                return true;
            } else {
                LOG_WARNING(QString("服务器报告传输失败: %1，尝试重发").arg(resultMessage));
            }
        } else {
            LOG_WARNING(QString("等待服务器传输完成确认超时 (尝试 %1/3)").arg(attempt));
            
            // 超时但最后一次尝试可能已经成功，我们假设服务器已经收到了
            if (attempt == 3) {
                LOG_INFO("最后一次尝试超时，假设服务器已成功接收文件");
                emit fileSendFinished(true, "文件可能已发送完成");
                return true;
            }
        }
        
        // 超时或失败，等待一会儿再尝试
        QThread::msleep(500);  // 减少重试等待时间
    }
    
    LOG_ERROR("发送文件传输完成消息失败，已达到最大尝试次数");
    emit fileSendFinished(false, "服务器未确认文件传输完成");
    return false;
}

bool Client::sendFile(const QString &filePath)
{
    if (!authenticated) {
        LOG_WARNING("发送文件失败: 未认证");
        emit fileSendFinished(false, "未认证，无法发送文件");
        return false;
    }
    
    LOG_INFO(QString("开始发送文件: %1").arg(filePath));
    
    // 暂停屏幕更新以提高文件传输速度
    bool wasReceivingScreenUpdates = isReceivingScreenUpdates();
    if (wasReceivingScreenUpdates) {
        LOG_INFO("暂停屏幕更新以提高文件传输速度");
        stopScreenUpdates();
    }
    
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly)) {
        LOG_ERROR(QString("无法打开文件: %1, 错误: %2").arg(filePath).arg(file.errorString()));
        emit fileSendFinished(false, "无法打开文件");
        
        // 如果之前正在接收屏幕更新，则恢复
        if (wasReceivingScreenUpdates) {
            LOG_INFO("恢复屏幕更新");
            startScreenUpdates();
        }
        return false;
    }
    
    QFileInfo info(filePath);
    QString fileName = info.fileName();
    qint64 fileSize = file.size();
    
    LOG_INFO(QString("文件信息: 名称=%1, 大小=%2字节").arg(fileName).arg(fileSize));
    
    // 生成唯一的传输ID
    QString transferId = "FileTransfer-" + QUuid::createUuid().toString();
    
    // 计算文件的MD5校验和
    QCryptographicHash md5(QCryptographicHash::Md5);
    QByteArray fileChecksum;
    
    if (fileSize < 100 * 1024 * 1024) { // 小于100MB的文件直接计算
        if (md5.addData(&file)) {
            fileChecksum = md5.result();
            LOG_INFO(QString("文件MD5校验和: %1").arg(QString(fileChecksum.toHex())));
            
            // 重置文件指针到开始位置
            file.reset();
        } else {
            LOG_WARNING("无法计算整个文件的MD5校验和，将逐块计算");
        }
    } else {
        LOG_INFO("文件较大，将逐块计算MD5校验和");
    }
    
    // 1. 发送文件请求，使用统一的传输ID
    QJsonObject req;
    req["fileName"] = fileName;
    req["fileSize"] = QString::number(fileSize);
    req["clientId"] = transferId;
    req["transferId"] = transferId;
    
    // 如果已计算出整个文件的校验和，则包含
    if (!fileChecksum.isEmpty()) {
        req["checksum"] = QString(fileChecksum.toHex());
    }
    
    LOG_INFO(QString("发送FileSendRequest消息，传输ID: %1").arg(transferId));
    
    // 尝试发送请求，最多尝试3次
    bool requestSent = false;
    for (int attempt = 1; attempt <= 3 && !requestSent; attempt++) {
        if (networkManager->sendData(MessageType::FileSendRequest, req)) {
            requestSent = true;
        } else {
            LOG_WARNING(QString("发送文件请求失败，尝试 %1/3").arg(attempt));
            QThread::msleep(1000); // 等待1秒再尝试
        }
    }
    
    if (!requestSent) {
        LOG_ERROR("发送文件请求失败，已达到最大尝试次数");
        emit fileSendFinished(false, "发送文件请求失败");
        
        // 如果之前正在接收屏幕更新，则恢复
        if (wasReceivingScreenUpdates) {
            LOG_INFO("恢复屏幕更新");
            startScreenUpdates();
        }
        return false;
    }
    
    // 等待服务器确认
    LOG_INFO("等待服务器确认...");
    QEventLoop loop;
    QTimer timeoutTimer;
    timeoutTimer.setSingleShot(true);
    bool serverReady = false;
    
    // 连接超时定时器
    connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit);
    
    // 设置接收服务器确认的处理函数
    auto confirmHandler = [this, &loop, &serverReady, transferId](MessageType type, const QJsonObject &data) {
        if (type == MessageType::FileSendRequest) {
            QString recvTransferId = data["transferId"].toString();
            if (recvTransferId == transferId) {
                LOG_INFO("收到服务器确认");
                serverReady = true;
                loop.quit();
                return true;
            }
        }
        return false;
    };
    
    // 临时注册消息处理函数
    networkManager->registerTemporaryHandler(confirmHandler);
    
    // 启动超时定时器并等待
    timeoutTimer.start(8000); // 增加到8秒超时
    loop.exec();
    
    // 检查是否收到了服务器准备就绪的确认
    if (!serverReady) {
        LOG_ERROR("等待服务器确认超时或未收到准备就绪确认");
        
        // 重试发送文件请求
        LOG_INFO("尝试重新发送文件传输请求...");
        networkManager->sendData(MessageType::FileSendRequest, req);
        
        // 再次等待响应
        serverReady = false;
        timeoutTimer.start(12000); // 再给12秒超时时间
        loop.exec();
        
        if (!serverReady) {
            LOG_ERROR("重试后仍未收到服务器响应，放弃传输");
            emit fileSendFinished(false, "服务器未响应文件传输请求");
            
            // 如果之前正在接收屏幕更新，则恢复
            if (wasReceivingScreenUpdates) {
                LOG_INFO("恢复屏幕更新");
                startScreenUpdates();
            }
            return false;
        }
    }
    
    // 2. 分块发送数据
    const int blockSize = 64 * 1024; // 增加到64KB
    qint64 totalSent = 0;
    int blockCount = 0;
    bool transferSuccess = true;
    int maxRetries = 5;  // 增加最大重试次数
    int totalRetries = 0; // 总重试次数，防止无限循环
    
    // 计算总块数
    int totalBlocks = (fileSize + blockSize - 1) / blockSize;
    
    // 限制总重试次数
    const int maxTotalRetries = totalBlocks * 3;
    
    LOG_INFO(QString("开始分块发送数据, 块大小: %1字节, 总块数: %2").arg(blockSize).arg(totalBlocks));
    
    // 创建数据块确认集合
    QSet<int> confirmedBlocks;
    QHash<int, int> blockRetries; // 记录每个块的重试次数
    
    // 循环读取文件并发送，直到所有块都被确认或达到最大重试次数
    while (confirmedBlocks.size() < totalBlocks && transferSuccess && totalRetries < maxTotalRetries) {
        // 重置文件指针，从头开始扫描
        file.seek(0);
        totalSent = 0;
        blockCount = 0;
        
        // 读取并发送每个块
        while (!file.atEnd() && transferSuccess) {
            // 如果当前块已确认，跳过
            if (confirmedBlocks.contains(blockCount)) {
                // 跳过这个块
                qint64 skipSize = std::min<qint64>(blockSize, fileSize - totalSent);
                file.skip(skipSize);
                totalSent += skipSize;
                blockCount++;
                continue;
            }
            
            // 读取数据块
            QByteArray block = file.read(blockSize);
            if (block.isEmpty()) {
                break;
            }
            
            // 为当前块计算MD5校验和
            QCryptographicHash blockMd5(QCryptographicHash::Md5);
            blockMd5.addData(block);
            QByteArray blockChecksum = blockMd5.result();
            
            // 压缩数据块
            QByteArray compressedBlock = compressData(block);
            bool isCompressed = (compressedBlock.size() < block.size());
            QByteArray dataToSend = isCompressed ? compressedBlock : block;
            
            LOG_INFO(QString("数据块 #%1: 原始大小=%2字节, 压缩后=%3字节, 压缩率=%4%")
                    .arg(blockCount)
                    .arg(block.size())
                    .arg(dataToSend.size())
                    .arg(isCompressed ? 100.0 - (dataToSend.size() * 100.0 / block.size()) : 0.0, 0, 'f', 1));
            
            // 准备数据包
            QJsonObject dataObj;
            dataObj["transferId"] = transferId;
            dataObj["clientId"] = transferId;
            dataObj["blockNumber"] = blockCount;
            dataObj["blockSize"] = block.size();
            dataObj["compressedSize"] = dataToSend.size();
            dataObj["compressed"] = isCompressed;
            dataObj["offset"] = totalSent;
            dataObj["data"] = QString::fromLatin1(dataToSend.toBase64());
            dataObj["checksum"] = QString(blockChecksum.toHex());
            dataObj["totalBlocks"] = totalBlocks;
            
            // 发送数据包
            LOG_INFO(QString("发送数据块 #%1/%2, 偏移量: %3, 大小: %4字节")
                    .arg(blockCount)
                    .arg(totalBlocks)
                    .arg(totalSent)
                    .arg(block.size()));
            
            bool blockSent = false;
            int currentRetries = blockRetries.value(blockCount, 0);
            
            // 如果已经尝试太多次，跳过这个块
            if (currentRetries >= maxRetries * 2) {
                LOG_WARNING(QString("数据块 #%1 已达到最大重试次数，跳过").arg(blockCount));
                totalSent += block.size();
                blockCount++;
                continue;
            }
            
            // 尝试发送块，最多重试maxRetries次
            while (!blockSent && currentRetries < maxRetries) {
                if (networkManager->sendData(MessageType::FileSendData, dataObj)) {
                    // 等待确认或超时
                    QEventLoop blockLoop;
                    QTimer blockTimer;
                    blockTimer.setSingleShot(true);
                    
                    connect(&blockTimer, &QTimer::timeout, &blockLoop, &QEventLoop::quit);
                    
                    // 设置接收块确认的处理函数
                    auto blockConfirmHandler = [this, &blockLoop, &blockSent, transferId, blockCount](MessageType type, const QJsonObject &data) {
                        if (type == MessageType::FileSendAck) {
                            QString recvTransferId = data["transferId"].toString();
                            int recvBlockNumber = data["blockNumber"].toInt();
                            bool success = data["success"].toBool();
                            
                            if (recvTransferId == transferId && recvBlockNumber == blockCount) {
                                if (success) {
                                    LOG_INFO(QString("数据块 #%1 已确认").arg(blockCount));
                                    blockSent = true;
                                } else {
                                    LOG_WARNING(QString("数据块 #%1 发送失败，需要重试").arg(blockCount));
                                }
                                blockLoop.quit();
                                return true;
                            }
                        }
                        return false;
                    };
                    
                    // 临时注册消息处理函数
                    networkManager->registerTemporaryHandler(blockConfirmHandler);
                    
                    // 启动超时定时器并等待，根据重试次数增加超时时间
                    blockTimer.start(2000 + currentRetries * 500); // 基础2秒 + 递增等待时间
                    blockLoop.exec();
                    
                    // 如果是由于超时退出的
                    if (!blockTimer.isActive() && !blockSent) {
                        LOG_WARNING(QString("数据块 #%1 确认超时，将重试").arg(blockCount));
                    }
                } else {
                    LOG_ERROR(QString("发送数据块失败 #%1").arg(blockCount));
                }
                
                currentRetries++;
                totalRetries++;
                blockRetries[blockCount] = currentRetries;
                
                if (!blockSent && currentRetries < maxRetries) {
                    LOG_INFO(QString("重试发送数据块 #%1 (尝试 %2/%3)").arg(blockCount).arg(currentRetries+1).arg(maxRetries));
                    QThread::msleep(100 * currentRetries); // 递增等待时间
                }
            }
            
            if (blockSent) {
                confirmedBlocks.insert(blockCount);
            } else {
                // 如果是最后的数据块，尝试再次重试
                if (blockCount >= totalBlocks - 3) {
                    LOG_WARNING(QString("最后的数据块 #%1 发送失败，将增加额外重试").arg(blockCount));
                    
                    // 额外重试次数
                    int extraRetries = 0;
                    int maxExtraRetries = maxRetries * 2;
                    
                    while (!blockSent && extraRetries < maxExtraRetries) {
                        if (networkManager->sendData(MessageType::FileSendData, dataObj)) {
                            // 等待确认或超时
                            QEventLoop extraBlockLoop;
                            QTimer extraBlockTimer;
                            extraBlockTimer.setSingleShot(true);
                            
                            connect(&extraBlockTimer, &QTimer::timeout, &extraBlockLoop, &QEventLoop::quit);
                            
                            // 设置接收块确认的处理函数
                            auto extraBlockConfirmHandler = [this, &extraBlockLoop, &blockSent, transferId, blockCount](MessageType type, const QJsonObject &data) {
                                if (type == MessageType::FileSendAck) {
                                    QString recvTransferId = data["transferId"].toString();
                                    int recvBlockNumber = data["blockNumber"].toInt();
                                    bool success = data["success"].toBool();
                                    
                                    if (recvTransferId == transferId && recvBlockNumber == blockCount) {
                                        if (success) {
                                            LOG_INFO(QString("数据块 #%1 已确认(额外重试)").arg(blockCount));
                                            blockSent = true;
                                        } else {
                                            LOG_WARNING(QString("数据块 #%1 发送失败(额外重试)").arg(blockCount));
                                        }
                                        extraBlockLoop.quit();
                                        return true;
                                    }
                                }
                                return false;
                            };
                            
                            // 临时注册消息处理函数
                            networkManager->registerTemporaryHandler(extraBlockConfirmHandler);
                            
                            // 启动超时定时器并等待，额外重试增加超时时间
                            extraBlockTimer.start(3000 + extraRetries * 500); // 增加超时时间
                            extraBlockLoop.exec();
                            
                            // 如果是由于超时退出的
                            if (extraBlockTimer.isActive()) {
                                extraBlockTimer.stop();
                                if (blockSent) {
                                    confirmedBlocks.insert(blockCount);
                                    break;
                                }
                            } else {
                                LOG_WARNING(QString("数据块 #%1 额外确认超时，将再次重试").arg(blockCount));
                            }
                        } else {
                            LOG_ERROR(QString("额外重试发送数据块失败 #%1").arg(blockCount));
                        }
                        
                        extraRetries++;
                        totalRetries++;
                        LOG_INFO(QString("额外重试发送数据块 #%1 (尝试 %2/%3)").arg(blockCount).arg(extraRetries+1).arg(maxExtraRetries));
                        QThread::msleep(200 * extraRetries); // 递增等待时间
                    }
                    
                    if (blockSent) {
                        confirmedBlocks.insert(blockCount);
                    } else {
                        LOG_ERROR(QString("数据块 #%1 发送失败，已达到最大额外重试次数").arg(blockCount));
                    }
                } else {
                    LOG_ERROR(QString("数据块 #%1 发送失败，已达到最大重试次数").arg(blockCount));
                }
            }
            
            if (!blockSent && !confirmedBlocks.contains(blockCount)) {
                // 即使某个块发送失败，也继续尝试发送其他块
                LOG_WARNING(QString("无法确认数据块 #%1，继续传输后续块").arg(blockCount));
            }
            
            // 更新计数器
            totalSent += block.size();
            blockCount++;
            
            // 发送进度
            double progress = (double)confirmedBlocks.size() / totalBlocks;
            emit fileSendProgress(confirmedBlocks.size(), totalBlocks);
            
            LOG_INFO(QString("进度: %1/%2 块 (%3%)")
                   .arg(confirmedBlocks.size())
                   .arg(totalBlocks)
                   .arg(int(progress * 100)));
            
            // 每发送10个数据块等待一下，避免网络缓冲区溢出
            if (blockCount % 10 == 0) {
                LOG_INFO("等待网络缓冲...");
                QThread::msleep(20); // 减少等待时间
            }
            
            // 处理事件循环，保持UI响应
            QCoreApplication::processEvents();
        }
        
        // 如果所有块都已确认，或者传输失败且缺少太多块，则退出
        if (confirmedBlocks.size() >= totalBlocks) {
            LOG_INFO("所有数据块已确认，准备完成传输");
            break;
        }
        
        // 如果缺少的块数太多，中断传输
        int missingBlocks = totalBlocks - confirmedBlocks.size();
        if (missingBlocks > totalBlocks / 3 && confirmedBlocks.size() < totalBlocks - 3) {
            LOG_ERROR(QString("缺少太多数据块 (%1/%2)，中断传输").arg(missingBlocks).arg(totalBlocks));
            transferSuccess = false;
            break;
        }
        
        // 进度统计
        LOG_INFO(QString("本轮结束，已确认 %1/%2 块，未确认 %3 块")
               .arg(confirmedBlocks.size())
               .arg(totalBlocks)
               .arg(totalBlocks - confirmedBlocks.size()));
        
        // 如果还有未确认的块，等待一段时间后继续尝试
        if (confirmedBlocks.size() < totalBlocks) {
            LOG_INFO("等待一段时间后继续尝试发送未确认的块...");
            QThread::msleep(1000);
        }
    }
    
    file.close();
    
    // 检查是否最后几个块未确认
    int missingBlocks = totalBlocks - confirmedBlocks.size();
    if (missingBlocks > 0) {
        LOG_WARNING(QString("文件传输结束，但有 %1 个块未得到确认").arg(missingBlocks));
        
        if (missingBlocks <= 3 || (totalBlocks > 10 && missingBlocks <= totalBlocks / 10)) {
            LOG_INFO("缺少的块数较少，继续尝试发送传输完成消息");
            transferSuccess = true; // 允许继续完成传输
        } else {
            LOG_ERROR(QString("缺少太多块 (%1/%2)，无法完成传输").arg(missingBlocks).arg(totalBlocks));
            transferSuccess = false;
        }
    }
    
    if (!transferSuccess) {
        emit fileSendFinished(false, QString("文件传输中断，缺少 %1/%2 个数据块").arg(missingBlocks).arg(totalBlocks));
        
        // 如果之前正在接收屏幕更新，则恢复
        if (wasReceivingScreenUpdates) {
            LOG_INFO("恢复屏幕更新");
            startScreenUpdates();
        }
        return false;
    }
    
    // 3. 等待一段时间确保所有数据都已发送
    LOG_INFO("等待数据发送完成...");
    QThread::msleep(500);
    
    // 4. 发送文件传输完成消息
    bool result = sendFileFinishMessage(transferId, fileName, fileSize, totalBlocks, fileChecksum);
    
    // 如果之前正在接收屏幕更新，则恢复
    if (wasReceivingScreenUpdates) {
        LOG_INFO("恢复屏幕更新");
        startScreenUpdates();
    }
    
    return result;
} 